﻿namespace OverStore.Runtime.Storage
{
    using System;
    using System.Collections.Generic;
    using System.Data;

    /// <summary>
    /// Define how the <see cref="AdoNetCommand"/> executes and how it returns results.
    /// <seealso cref="AdoNetCommand"/>
    /// </summary>
    /// <remarks>
    /// <para>
    /// The way how the <see cref="AdoNetCommand"/> executes defines by invoked <see cref="AdoNetStorage{TConnection}"/> method where the command
    /// used as argument. Some <see cref="AdoNetStorage{TConnection}"/> methods executes command in single way, other supports multiple way to
    /// execute command.
    /// </para>
    /// <para>
    /// The <see cref="AdoNetStorage{TConnection}.ReadAll"/> method always executes command in the same way, by opening <see cref="IDataReader"/>.
    /// When command used as argument of <see cref="AdoNetStorage{TConnection}.ReadAll"/>, the result of <see cref="AdoNetCommand.ResultGettingType"/> property 
    /// is ignored.
    /// </para>
    /// <para>
    /// The <see cref="AdoNetStorage{TConnection}.Execute"/> method supports all AdoCommandResultType values, but by default the 
    /// <c>AdoCommandResultType.DataReaderResultSet</c> is used.
    /// </para>
    /// </remarks>
    public enum AdoCommandResultType
    {
        /// <summary>
        /// <para>
        /// <see cref="AdoNetCommand"/> returns it's results via output parameters result. If command does not contain 
        /// any output parameters, the input parameter' values are used.
        /// </para>
        /// </summary>
        OutputParameters,

        /// <summary>
        /// <para>
        /// <see cref="AdoNetCommand"/> executes <see cref="IDataReader"/> and uses it's data as command result. The 
        /// <see cref="AdoNetStorage{TConnection}.Execute"/> methods uses 
        /// only first row from resultset. If commands returns empty resultset, the command returns empty record.
        /// </para>
        /// </summary>
        DataReaderResultSet,

        /// <summary>
        /// <para>
        /// <see cref="AdoNetCommand"/> uses output parameter values, and also executes <see cref="IDataReader"/>. 
        /// </para>
        /// <para>
        /// Both results are merged into one, if result with the same name exists both in reader and output parameters,
        /// result from Data Reader's resultset is used.
        /// </para>
        /// </summary>
        MergePreferResultSet,

        /// <summary>
        /// <para>
        /// <see cref="AdoNetCommand"/> uses output parameter values, and also executes <see cref="IDataReader"/>. 
        /// </para>
        /// <para>
        /// Both results are merged into one, if result with the same name exists both in reader and output parameters,
        /// result from output parameter's is used.
        /// </para>
        /// </summary>
        MergePreferOutputParameters
    }

    /// <summary>
    /// Base class for <see cref="ICommand"/> works with ADO.NET
    /// </summary>
    public abstract class AdoNetCommandBase : ICommand
    {
        /// <summary>
        /// Executes current command using specified <see cref="IDbCommand"/> and read all data from resultset returned.
        /// </summary>
        public abstract IEnumerable<TypedRecord> ReadAll(Func<AdoNetCommandBase, DataCommandContainer> createCommand, IRecord parameters);

        /// <summary>
        /// Executes specified command and return command result.
        /// </summary>
        public abstract TypedRecord Execute(Func<AdoNetCommandBase, DataCommandContainer> createCommand, IRecord parameters, out int rowsAffected);
    }
}
